package com.lichuandi.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Aspect // 声明为切面类
@Component // 纳入 Spring 容器管理
public class LoggingAspect {

    // 切入点定义：匹配 com.example.service 包下所有类的所有方法。定义切入点表达式，可复用

    /**
     * 常见切入点表达式：
     * 包路径匹配
     * execution(* com.example.service.*.*(..))
     * 注解匹配
     * @annotation(com.example.anno.CustomLog)
     *
     * 组合表达式
     * @Pointcut("execution(* com..service.*.*(..)) && @annotation(log)")
     */
    @Pointcut("execution(* com.lichuandi.service.*.*(..))")
    public void serviceLayer() {}

    // 前置通知 方法执行前执行
    @Before("serviceLayer()")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("调用方法: " + joinPoint.getSignature().getName());
        System.out.println("参数: " + Arrays.toString(joinPoint.getArgs()));
    }

    // 返回后通知 方法正常返回后执行（可获取返回值）
    @AfterReturning(pointcut = "serviceLayer()", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("方法返回: " + result);
    }

    // 异常通知 方法抛出异常后执行
    @AfterThrowing(pointcut = "serviceLayer()", throwing = "ex")
    public void logAfterThrowing(JoinPoint joinPoint, Exception ex) {
        System.out.println("方法异常: " + ex.getMessage());
    }

    // 环绕通知（功能最强大） 无论是否异常都会执行（类似 finally）
    @Around("serviceLayer()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed(); // 执行目标方法
        long elapsed = System.currentTimeMillis() - start;
        System.out.println("方法执行耗时: " + elapsed + "ms");
        return result;
    }
}